package com.ryl.yomall.gateway.filter;


import com.alibaba.fastjson.JSONObject;
import com.ryl.yomall.gateway.constant.RedisConst;
import com.ryl.yomall.model.common.result.Result;
import com.ryl.yomall.model.common.result.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * @Date 9:06
 * @Author ryl
 *    自定义全局过滤器
 *    判断用户是否登录
 *    1.不用登录
 *    2.可以登录或者不登陆
 *    3.必须登录
 *    4.内部资源,不永许访问
 */
@Component
public class LoginGlobalFilter implements GlobalFilter, Ordered {

    private AntPathMatcher antPathMatcher = new AntPathMatcher (  );
    public static final String TOKEN="token";
    //临时用户ID
    public static final String USERTEMPID = "userTempId";
    @Autowired
    private RedisTemplate redisTemplate;
    @Value ( "${auth.url}" )
    private String[] authUrls;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange ,GatewayFilterChain chain) {
        // exchange 交换机 ==请求对象 响应对象
        ServerHttpRequest request = exchange.getRequest ( );
        ServerHttpResponse response = exchange.getResponse ( );
        System.out.println ("getPath"+request.getPath () );
        System.out.println (request.getURI ().getRawSchemeSpecificPart () );
        System.out.println ("get.url.path:"+request.getURI ( ).getPath ( ) );

        System.out.println ("getHostName:"+request.getRemoteAddress ().getHostName () );
        System.out.println ("getHostString:"+request.getRemoteAddress ().getHostString () );
        ////////////////////以下为正式代码//////////////////////////
        //哪些微服务走网关  ： 用户微服务 商品微服务 搜索微服务 异步 同步
        //  VUE  访问网关  路由 某一个微服务  异步的 Json串
        //  搜索微服务 Feign远程调用 商品微服务 异步 json
        // Html 访问网关  路由 页面微服务 页面渲染 同步
        //结论： 如下
        //1:内部资源  转发  商品微服务 /inner 不允许
        //2：异步：未登录  返回值 Result.fail  LOGIN_AUTH(208, "未登陆"), JSON格式字符串 返回
        //页面上208时 将早早准备好弹出层 弹出来 让用户去登录
        //3：同步： 未登录  重定向  去登录页面

        //获取当前路径
        String path=request.getURI ().getPath ();
        if(antPathMatcher.match ( "/**/inner/**",path )){
            //内部资源.无权访问
            return out ( response,ResultCodeEnum.PERMISSION );

        }
        String userId=getUserId(request);
        //异步请求中,必须登录 /**/auth/**
        if(antPathMatcher.match ( "/**/auth/**" ,path)){
            //必须登录 ,获取用户ID

            if(StringUtils.isEmpty ( userId )){
                return out ( response,ResultCodeEnum.LOGIN_AUTH );
            }
        }
        //同步:trade.html pay.html
        for (String authUrl : authUrls) {
            if(path.contains ( authUrl ) && StringUtils.isEmpty ( userId )){
              //未登录,从定向到登录页面
                response.setStatusCode ( HttpStatus.SEE_OTHER ); //从定向
                try {
                    response.getHeaders ().add ( HttpHeaders.LOCATION,
                            "//passport.yomall.com/login.html?originUrl="
                                    + URLEncoder.encode(
                                    request.getURI().getRawSchemeSpecificPart(),"utf-8") );
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace ( );
                }
                return response.setComplete ();//响应完成
            }
        }
        if(null != userId){
            //设置新的请求头,设置用户id,转发购物车微服务
            request.mutate ().header ( "userId",userId );
        }
        String userTempId=getUserTempId ( request );
        if(null != userTempId){
            //设置新的请求头,设置用户id,转发购物车微服务
            request.mutate ().header ( "userTempId",userTempId );

        }

        //放行 进入下一个过滤器 转发微服务
        return chain.filter ( exchange );

    }
    //统一异步请求返回值
    private Mono<Void> out(ServerHttpResponse response,ResultCodeEnum resultCodeEnum){
        Result result = Result.build(null,resultCodeEnum);
        //转成Json串
        String json = JSONObject.toJSONString(result);
        //响应
        DataBufferFactory dataBufferFactory = response.bufferFactory();
        DataBuffer dataBuffer = dataBufferFactory.wrap(json.getBytes());
        response.getHeaders().add( HttpHeaders.CONTENT_TYPE,
                "application/json;charset=UTF-8");
        return  response.writeWith(Mono.just(dataBuffer));
    }
    //获取临时用户Id
    private String getUserTempId(ServerHttpRequest request) {
        //1:请求头中
        String userTempId = request.getHeaders().getFirst(USERTEMPID);
        if(StringUtils.isEmpty(userTempId)){
            //2:Cookie中
            HttpCookie cookie = request.getCookies().getFirst(USERTEMPID);
            if(null != cookie){
                userTempId = cookie.getValue();
            }
        }
        return userTempId;
    }
    //获取用户Id
    private String getUserId(ServerHttpRequest request) {
        //1.用户id请求头中
        String token = request.getHeaders ( ).getFirst ( TOKEN );
        if(StringUtils.isEmpty ( token )){
            //2.Cookie中
            HttpCookie cookie = request.getCookies ( ).getFirst ( TOKEN );
            if( null != cookie){
                token= cookie.getValue ( );

            }
        }
        if(token != null){
            //获取到token,从redis中获取用户id
            if(redisTemplate.hasKey ( RedisConst.USER_LOGIN_KEY_PREFIX+token )){

             return (String) redisTemplate.opsForValue ().get ( RedisConst.USER_LOGIN_KEY_PREFIX+token );
            }
        }


        return null;
    }

    //排序 默认有9大全局过滤器+自定义过滤器
    //整数最小 执行优先级最高
    @Override
    public int getOrder() {

        return 0;
    }
}
